package com.mtwp.dfs.service.category.stateprocess;

import com.mtwp.dfs.domain.category.DiskStore;
import com.mtwp.dfs.domain.category.FileType;
import com.mtwp.dfs.repository.DiskStoreRepository;
import com.mtwp.dfs.repository.FileTypeRepository;
import com.mtwp.dfs.service.category.DiskStoreService;
import com.mtwp.dfs.service.category.stateprocess.child.AuthFuncMap;
import com.mtwp.dfs.service.dfs.FastDFSService;
import com.twp.common.component.process.statemachine.annotation.IMapFunction;
import com.twp.common.component.process.statemachine.annotation.IMapFunctionListenerProcess;
import com.twp.common.component.process.statemachine.annotation.MapFunctionListener;
import com.twp.common.component.process.statemachine.base.DefaultStateNodeComponent;
import com.twp.common.component.process.statemachine.domain.StateNode;
import com.twp.common.component.process.statemachine.domain.iinterface.IMapRouterProcessStateNodeFunc;
import com.twp.common.component.process.statemachine.translate.ITranslateState;
import com.twp.common.tuple.ResultDTO;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.io.FileUtils;
import org.javatuples.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.security.Principal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/*
云存储相关的状态机
 */
@Service
@Slf4j
@Builder
public class DFSFuncMap implements IMapFunction {

    @Autowired
    FastDFSService fastDFSService;

    @Autowired
    DiskStoreService diskStoreService;

    @Autowired
    FileTypeRepository fileTypeRepository;

    @Autowired
    ITranslateState<StateNode,Map,Map<StateNode,IMapRouterProcessStateNodeFunc<StateNode>>,ResultDTO,Exception> iTranslateState;

    @Autowired
    IMapFunctionListenerProcess<StateNode,Map<StateNode,IMapRouterProcessStateNodeFunc<StateNode>>> iMapFunctionListenerProcess;

    @Autowired
    DiskStoreRepository diskStoreRepository;

    @Autowired
    AuthFuncMap authFuncMap;

    /*
    状态入口：存储操作请求检查
     */
    @MapFunctionListener(name = "存储操作请求检查",group = "dfs_action",code = "requestEnter")
    public StateNode dealRequestEnter(StateNode currentNode){
        log.info("存储操作请求检查");
        /*
        检查权限的子状态机
        启动子状态机
         */
        ResultDTO authResultDTO = new DefaultStateNodeComponent(authFuncMap){
            @Override
            public StateNode onCreate() {
                return StateNode
                        .builder()
                        .nodeCode("dfs_auth_start")
                        .requestDto(currentNode.getRequestDto())
                        .build();
            }

            @Override
            public Pair<Map, StateNode> onStart() {
                return Pair.with(new HashMap(),new StateNode().setNodeCode("dfs_auth_end"));
            }

            @Override
            public void onException(Exception e) {

            }

            @Override
            public void onDestroy() {

            }
        }.setIMapFunctionListenerProcess(iMapFunctionListenerProcess).setITranslateState(iTranslateState).runOnResp();
        /*
        拿到子检查状态机的结果回归主线状态机匹配
         */
        if(authResultDTO.getIsSuccess()){
            return StateNode.builder().requestDto(currentNode.getRequestDto()).nodeCode("dfs_action_match").build();
        }
        //否则进入交易异常
        return StateNode.builder().response(authResultDTO).nodeCode("dfs_action_exception").build();
    }


    @MapFunctionListener(name = "存储操作请求处理",group = "dfs_action",code = "match")
    public StateNode businessMatch(StateNode<DiskStore,ResultDTO> currentNode){
        log.info("business_match");
        /*
        上传到dfs之前需要做存储记录与存储节点的检查
        可以依据实际情况选择是否分离子状态机
         */
        // 先完成功能，后续分离
        /*
        简单处理
        执行存储
         */
        val requestDto = currentNode.getRequestDto();
        Principal principal = requestDto.getPrincipal();
        DiskStore diskStore = requestDto.getData();
        Date d = new Date();

        MultipartFile multipartFile = diskStore.getFile();
        String[] nameArr = multipartFile.getOriginalFilename().split("\\.");
        diskStore.setName(nameArr[0]);
        diskStore.setExtension(nameArr[1]);
        if (diskStore.getFileType()!=null){
            FileType fileType = fileTypeRepository.findOne(diskStore.getFileType().getId());
            diskStore.setFileType(fileType);
        }
        //设置文件容量
        diskStore.setCapacity(FileUtils.byteCountToDisplaySize(multipartFile.getSize()));
        diskStore.setUpdateTime(d);
        diskStore.setCreateTime(d);
        //diskStore.setName()
        try {
            String downloadUrl = fastDFSService.uploadFile(principal.getName(),multipartFile);
            diskStore.setDownloadUrl(downloadUrl);
            diskStoreService.saveOrUpdate(diskStore);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return StateNode.builder().nodeCode("dfs_action_end").response(ResultDTO.builder().message("存储操作请求处理结束").build()).build();
    }

    @MapFunctionListener(name = "存储操作请求处理结束",group = "dfs_action",code = "end")
    public StateNode dealEnd(StateNode currentNode){
        log.info("存储操作请求处理结束");
        if (currentNode.getResponse()!=null&&!currentNode.getResponse().getIsSuccess()){
            return StateNode.builder().response(
                    currentNode.getResponse()
                    )
                    .build();
        }
        return StateNode.builder().response(
                ResultDTO
                        .builder()
                        .message("存储操作请求处理结束")
                        .data(currentNode.getResponse())
                        .build())
                .build();
    }

    @MapFunctionListener(name = "存储操作请求处理异常",group = "dfs_action",code = "exception")
    public StateNode dealException(StateNode currentNode){
        /*
        异常的处理
         */
        /*
        最终返回给结束节点
         */
        return StateNode
                .builder()
                .nodeCode("dfs_action_end")
                .response(
                        ResultDTO
                                .builder()
                                .message("异常正常捕获")
                                .isSuccess(false)
                                .data(currentNode.getResponse())
                                .build()
                )
                .build();
    }
}
